﻿using ElasticReflection.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ElasticReflection
{
    public static class ElasticTypeExtensions
    {

        public static ElasticType ToElastic(this Type Type)
        {
            return ElasticType.Create(Type, null);
        }
        public static ElasticType Type(this object o)
        {
            return ElasticType.Create(o.GetType(), o);
        }


    }


    public static class ElasticMethodExtensions
    {
        public static IEnumerable<ElasticMethod> Method(this object o, string Name, params Type[] Generics)
        {
            return o.Type().Method(Name, Generics);
        }
        public static IEnumerable<ElasticMethod> Method(this Type T, string Name, params Type[] Generics)
        {
            return T.ToElastic().Method(Name, Generics);
        }

        public static object Call(this IEnumerable<ElasticMethod> Methods, params object[] Parameters)
        {
            var Types = Parameters.Select(p => p.GetType());
            var matchedMethods = Methods.Where(m => m.Base.GetParameters().Select(p => p.ParameterType).SequenceEqual(Types));
            if (matchedMethods.Count() == 1) return matchedMethods.First().Call(Parameters);

            throw new InvalidParametersException();

        }

    }
    public static class ElasticPropertyExtensions
    {
        public static ElasticProperty Property(this object o, string Name)
        {
            return o.Type().Property(Name);
        }
        public static ElasticProperty Property(this Type Type, string Name)
        {
            return Type.ToElastic().Property(Name);
        }
        public static IEnumerable<ElasticProperty> Properties(this object o)
        {
            var T = o.GetType().ToElastic();
            T.Instance = o;

            var Properties = T.Base.GetProperties();
            return Properties.Select(p => new ElasticProperty(T, p));
        }

    }
    public static class ElasticEventExtensions
    {
        public static ElasticEvent Event(this object o, string Name)
        {
            return o.Type().Event(Name);
        }
        public static ElasticEvent Event(this Type Type, string Name)
        {
            return Type.ToElastic().Event(Name);
        }

    }


}
